home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-08-05 | 50.7 KB | 2,027 lines |
- Newsgroups: comp.sources.misc
- organization: Cetia, Toulon, France
- subject: v07i116: nlist -- display and monitor kernel variables and data structures
- from: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Reply-To: chris@cetia.UUCP (Chris Bertin)
-
- Posting-number: Volume 7, Issue 116
- Submitted-by: chris@cetia.UUCP (Chris Bertin)
- Archive-name: nlist
-
- [Amazing. It looks like this should be easy to adapt to almost any flavor
- of Unix; it comes with SunOS 3.5, 4.3BSD, and System V R2 and R3 templates.
- Horray for portable programming! ++bsa]
-
- This is 'nlist'. There is a README file and manual that explain what it does,
- as well as a few examples of the things you can do with it. I tried posting
- it to comp.sources.unix, but nothing seems to be going on with that group any
- more (the last posting I received from comp.sources.unix is from the first
- of July...). I am not even getting replies to my mail to Rich Salz.
-
- Anyway, if you have any questions, please email them to me.
-
- Chris
-
- ---------------------------------- cut here -------------------------------
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # README
- # MANIFEST
- # nlist.8
- # nlist.c
- # Makefile
- # chars.sun
- # config.sh
- # dnlc.sun
- # file.sun
- # file.sys53
- # minfo.sys5
- # mount.sun
- # mount.sys53
- # syserr.sys5
- # sysinfo1.sys5
- # sysinfo2.sys5
- # sysinfo3.sys5
- # sysinfo4.sys5
- # sysinfo5.sys5
- # sar-s
- # This archive created: Wed Aug 2 17:52:40 1989
- export PATH; PATH=/bin:/usr/bin:$PATH
- if test -f 'README'
- then
- echo shar: "will not over-write existing file 'README'"
- else
- cat << \SHAR_EOF > 'README'
-
- -- N L I S T --
-
- To make 'nlist', type 'sh config.sh'. I have built it on SYSV.2, SYSV.3,
- SunOs3.5, BSD4.3 and Mach, so I hope it will compile and run without
- problems on your system.
-
- There are examples for Sun machines in *.sun and examples for System V
- machines in *.sys5*. BSD4.3 systems should be able to run some of the Sun
- scripts. If these scripts don't work on your machine, it means
- the structures are not quite identical to the ones I have here. It should
- be pretty easy to fix them, once you've read the manual. If symbols are not
- found, try adding or removing the leading symbol name underscore.
-
- If you have any comments, you can Email them to me.
-
- Chris Bertin | -- CETIA -- 150, Av Marcelin Berthelot, Z.I. Toulon-Est
- +33(94)212005 | 83088 Toulon Cedex, France
- | inria!cetia!chris
- SHAR_EOF
- fi
- if test -f 'MANIFEST'
- then
- echo shar: "will not over-write existing file 'MANIFEST'"
- else
- cat << \SHAR_EOF > 'MANIFEST'
- README
- MANIFEST
- nlist.8
- nlist.c
- Makefile
- chars.sun
- config.sh
- dnlc.sun
- file.sun
- file.sys53
- minfo.sys5
- mount.sun
- mount.sys53
- syserr.sys5
- sysinfo1.sys5
- sysinfo2.sys5
- sysinfo3.sys5
- sysinfo4.sys5
- sysinfo5.sys5
- sar-s
- SHAR_EOF
- fi
- if test -f 'nlist.8'
- then
- echo shar: "will not over-write existing file 'nlist.8'"
- else
- cat << \SHAR_EOF > 'nlist.8'
- .TH NLIST 8 LOCAL
- .SH NAME
- .ad b
- nlist \- display and monitor kernel variables and data structures
- .SH SYNOPSIS
- .B nlist
- [-aptux] [-f format] [-h header] [-l loops] [-m mem]
- .if n \{\
- .br
- .ti 2c\}
- [-n namelist] [-s sleep] [-D debug] symbol|formula ...
- .SH DESCRIPTION
- .I Nlist
- reads kernel variables and displays them. It can be used to monitor variables
- or to display arrays of data structures or linked lists. It is also a full
- report generator, with a built-in calculator. It is very useful for kernel
- debugging (monitoring of debug variables, for example) and can even provide
- a user-configurable replacement for utilities like
- .I sar(1),
- on SYSV systems.
- See the EXAMPLE section below.
- .PP
- The toggle options are:
- .TP 12
- .I -a
- Auto increment the address by the size of the previous read. This is used
- to step through a structure with a minimum amount of address calculations.
- The auto-increment option is disabled if the cell contains any address
- calculation. See the SYMBOLS, FORMULAS and EXAMPLES sections.
- .TP
- .I -p
- Prepend the '0x' prefix, if the display type is in hexadecimal, or the '0'
- prefix if it is in octal. Essentially the '#' option of printf.
- .TP
- .I -t
- Print the time in the first column (ala 'sar').
- .TP
- .I -u
- Print unique lines only (excluding the time, if the -t flag is present).
- .TP
- .I -x
- Normally,
- .B nlist
- exits if a value doesn't fit in the print format, or if a symbol is not
- found in the name list. If this option is present,
- .B nlist
- will carry on silently. See the
- .B format
- option below. Also, if this flag is set and if a read failure occurs,
- the output will be a string of question marks (?).
- .PP
- The other options are:
- .TP 12
- .I -f format
- The argument is a simplified printf format: a number followed by a valid
- format type. See the FORMATS section below.
- .TP
- .I -h header
- If the argument is zero (0), no title will be printed. If it is one (1),
- a title is printed on the first line only. If it is any other value, the
- title will be reprinted every ${LINES} (24 by default).
- .TP
- .I -l loops
- Normally,
- .B nlist
- loops forever. The argument is the number of lines that will
- be displayed, excluding the headers.
- .TP
- .I -m memdev
- Read kernel memory from
- .B memdev
- instead of the default
- .B /dev/kmem.
- .TP
- .I -n namelist
- Read the namelist from
- .B namelist
- instead of
- .B /unix
- or
- .B /vmunix.
- .TP
- .I -s sleep
- The argument overrides the default one (1) second pause between line output.
- .TP
- .I -D debug
- This field is a level of debug. One (1) prints information about the read's,
- two (2) prints the control structure before it is analyzed, and
- three (3) prints it after it has been analyzed. See source code for details.
- .PP
- The arguments following these options are kernel symbols or formulas. They
- will be refered to as
- .I cells
- in this manual.
- .SH SYMBOLS
- A symbol is a valid name found in the kernel namelist. A read size may be
- supplied after the symbol name, following the special character
- .B '|'.
- If the print format is not a string (see FORMATS below), only sizes
- of 1, 2 and 4 may be given, meaning the symbol to be read is 1, 2 or 4 bytes
- big. The default is 4.
- .PP
- Symbols may be also followed by a positive or negative offset indicated by
- .I +value
- or
- .I -value.
- .PP
- They may also be followed by a positive or negative loop increment, following
- the special character
- .B '>':
- .I >value,
- or
- .I >+value,
- or
- .I >-value.
- .PP
- Loop incrementing is done for each line, after all the arguments have been
- evaluated. It differs from the 'auto-increment' option which will increment
- the address of each cell with the read size of the preceding one, before the
- read is done.
- .PP
- These values may be given in any order.
- .PP
- If a symbol name is followed by an exclamation mark ('!'), the read will
- be done once only and the cell won't be printed.
- .SH FORMULAS
- .B Nlist
- has a built-in stacking (reverse Polish) calculator. Arithmetic
- operations may be performed on any current value, preceding value or address
- of any field (cell). The first non-option argument is cell one (1).
- .PP
- The special characters are:
- .TP 6
- .I '#'
- means the current value of a cell. That value is the value read from memory
- or whatever may have been placed there by a
- calculation.
- .TP
- .I '^'
- means the value of a cell on the previous pass.
- .TP
- .I '&'
- means the address of a cell. The address is the memory location from which
- data is read.
- .PP
- The cell identification may be absolute or relative and the special
- character '.' means the current cell. For example, '&.' is the read-address
- for the current cell, '#1' is the current value of cell 1, '^+3' is
- the value of the third cell to the right, on the previous pass, and '#-2' is
- the current value of the second cell on the left.
- .PP
- The valid operations are: +, -, * or / for add, subtract, multiply or divide,
- respectively. The operands may be integers, current cell values, previous
- cell values or read-addresses.
- .PP
- Additionally, values or addresses may be initialized or recalculated on every
- pass, using the
- .B '!'
- and the
- .B '=',
- special symbols respectively. For example:
- .PP
- .ti 10
- .B "#. = &-1 #-2 +"
- .PP
- will set the current value to the sum of the read-address of the preceding
- cell and the current value of the second cell on the left.
- .PP
- .ti 10
- .B "^+1 ! 1"
- .PP
- will initialize the previous value of the cell on the right to one (1).
- Note that initialization cells are not printed.
- .PP
- If the
- .B -x
- flag is set, divisions by zero (0) return an error instead of causing
- .B nlist
- to exit.
- .PP
- Floating point exceptions, except divisions by zero caught by the
- calculator, are always fatal.
- .SH CONDITIONAL EVALUATION
- If a question mark ('?') is found it the argument, it indicates that
- the read address for the current cell has been calculated by another cell
- and that the read should take place only if the read-address is non-zero.
- Following cells will be skipped as well and the value displayed will be a
- string of dashes ('-'). Reading will resume on the next cell that contains
- a real symbol, or on the next line, which ever comes first.
- .SH FORMATS
- The global print format is set to hexadecimal, 8 characters wide, by default.
- It may be modified globally using the
- .I -h
- flag, or for each cell. The syntax of a format cell is: the special character
- .B '%',
- optionally followed by a positive value and followed by a identifier.
- .PP
- Formats supported are: %d, %u, %o, %x, %f (2 decimals), %s and %t. %t is
- time format, meaning the value is printed using ctime(3).
- .PP
- The optional value is the width of the cell. If an overflow occurs,
- .B nlist
- will exit, unless the
- .B -x
- flag is set, in which case a string of asterisks (*) will be displayed.
- .PP
- If the format is decimal and if the result of a calculation is not an integer,
- floating point format will be used automatically.
- .SH HEADERS
- Each cell may supply its own header, after the special character
- .B ':'.
- If the header contains characters special to
- .B nlist,
- it must be quoted. If no header is supplied, the argument is printed.
- .SH EXAMPLES
- Here are now a few examples that will show most of the things
- that can be done with
- .B nlist:
- .PP
- Example 1
- .PP
- This command works on BSD and V7 systems that keep track of the
- total number of characters input and output, in '_tk_nin' and '_tk_nout',
- respectively.
- .PP
- .nf
- nlist -t -f 9d -s 2 \\
- _tk_nin \\
- _tk_nout \\
- '#. = #1 #2 + : Total' \\
- '#1 100 * #3 / : "% Input"' \\
- '#2 100 * #3 / : "% Output"'
- .fi
- .PP
- Description, argument by argument:
- .PP
- The time will be printed at the start of each line (-t option), the print
- mode will be decimal, 9 characters wide, for all the cells (-f 9d),
- and the program will run continuously with a line of output
- every 2 seconds (-s 2).
- .PP
- The value of '_tk_nin' will be read into cell 1, the value of '_tk_nout' into
- cell 2, the sum of these 2 values will be placed in the current value
- of cell 3.
- .PP
- Cells 4 and 5 will print out the percentages of inputs and outputs
- respectively.
- .PP
- The result will be something like:
- .PP
- .TS
- rrrrrr.
- 16:18:39 _tk_nin _tk_nout Total % Input % Output
- 16:18:39 19160 994283 1013443 1.89 98.11
- 16:18:41 19160 994343 1013503 1.89 98.11
- 16:18:43 19160 994403 1013563 1.89 98.11
- 16:18:45 19160 994463 1013623 1.89 98.11
- .../...
- .TE
- .PP
- Example 2
- .PP
- This command works on a Sun 3, with a release 3.5EXPORT. If the
- mount structure hasn't changed on newer releases, it will work as well. It
- should also work on generic 4.3 BSD systems.
- .PP
- This example uses different print formats, different read sizes,
- loop increments and cell auto-increments.
- .PP
- .nf
- nlist -pax -s 0 -f 8x -l 4 \\
- '^. 1 + : " #" %2d' \\
- '_mounttab>28 : Vfsp' \\
- ' |1 : Maj %3o' \\
- ' |1 : Min %3o' \\
- ' : Devvp' \\
- ' : Bufp' \\
- ' : Qinod' \\
- ' : Qflags |2' \\
- ' : Btime %5d' \\
- ' : Ftime %5d'
- .fi
- .PP
- Description, argument by argument:
- .PP
- Turn the 'prefix' option (-p), turn on the 'auto-increment' option (-a),
- continue if an overflow occurs (-x), don't pause between line displays (-s 0),
- use hexadecimal, 8 characters wide as a default print mode (-f 8x), and
- print out 4 lines (-l 4).
- .PP
- The next argument, on the next line, will just print a header by taking the
- value of the current cell on the previous pass (uninitialized, zero) and
- adding one (1) to it. Its header will be ' #' and its print format 2 decimal
- characters.
- .PP
- The next argument will cause the variable '_mounttab' to be read in and to
- be displayed with the 'Vfsp' title. When all the arguments will be processed,
- the address will be incremented by 28 (the size of the mount table
- structure). The read-address will be incremented by 4 for the next read,
- because auto-increment is turned on and because the read size is 4
- bytes (default).
- .PP
- The next 2 arguments will read 1 byte each (half a 'dev_t' type, on BSD),
- and display them as 'Maj' and 'Min', in octal, 3 characters wide.
- .PP
- The next 3 arguments are pointers, 4 bytes big. These cells are basically
- empty cells with a title (':').
- .PP
- The following argument is a short and the last 2 are longs, displayed in
- decimal, 6 characters wide.
- .PP
- The output will look something like this:
- .PP
- .if t \{\
- .TS
- rrrrrrrrrr.
- # m_vfsp maj min devvp bufp qinod qflags btime ftime
- 1 0x110b50 03 0 0x110afc 0x10213c 0 0 0 0
- 2 0x104400 07 0 0x1044f4 0x10125c 0 0 0 0
- 3 0x104424 03 03 0x110fc8 0x102208 0 0 0 0
- 4 0x104594 03 07 0x1044cc 0x1013f4 0 0 0 0
- .TE\}
- .if n \{\
- .nf
-
- # m_vfsp maj min devvp bufp qinod qflags btime ftime
- 1 0x110b50 03 0 0x110afc 0x10213c 0 0 0 0
- 2 0x104400 07 0 0x1044f4 0x10125c 0 0 0 0
- 3 0x104424 03 03 0x110fc8 0x102208 0 0 0 0
- 4 0x104594 03 07 0x1044cc 0x1013f4 0 0 0 0
- .fi\}
- .PP
- Example 3
- .PP
- This command will dump the 'dnlc' cache on a Sun. It uses the string output
- format and the addressing feature needed to follow linked lists. It should
- work without too many modifications on generic 4.3 systems.
- .PP
- .nf
- nlist -ax -h1 -s 0 -f6x -l 10 \\
- '_ncache : Hshnxt' \\
- ' : Hshprv' \\
- ' : Lrunxt' \\
- ' : Lruprv' \\
- ' : Vp' \\
- ' : Dp' \\
- '|1 : Len %3d' \\
- '|15 : Name %15s' \\ <== 8
- ' : Ucred' \\
- '@&1 = #1' <== 10
- .fi
- .PP
- Description of arguments not yet explained.
- .PP
- The argument on the 8th line displays a string of
- characters, 15 bytes long.
- .PP
- The last (10th) argument shows how one can follow a linked list. The '@'
- means that the cell won't be printed, '&1 = #1' sets
- the address of the first cell to the value of the first cell.
- .PP
- Here is the result:
- .PP
- .if t \{\
- .TS
- rrrrrrrrr
- rrrrrrrlr.
- Hshnxt Hshprv Lrunxt Lruprv Vp Dp Len Name Ucred
- a02e0 0 a051c a0e38 a1db0 a1ac4 0 ......\\.......\\ a1518
- a1360 a051c a1728 a0fc4 92b6c 9242e 3 usrxcvsub.c0or0 0
- a1ddc a02e0 a1964 a190c 92834 90668 11 usr.MC68010nd.o 0
- a16d0 a1360 a138c a0de0 95070 92b6c 5 spool.heds40.os 0
- a17d8 a1ddc a117c a1200 96962 92766 3 ucbf.hub.cld.av 0
- a0a9c a16d0 a0860 a0390 93c52 97be4 7 nlist.oa1.c.old 0
- a10cc a17d8 a030c a1d00 95a18 92dd6 2 ldrace.h.c30rc1 0
- a0cd8 a0a9c a1bcc a093c 92c3a 95476 6 time.hh0p@svc.2 0
- .../...
- .TE\}
- .if n \{\
- .nf
- Hshnxt Hshprv Lrunxt Lruprv Vp Dp Len Name Ucred
- a02e0 0 a051c a0e38 a1db0 a1ac4 0 ......\\.......\\ a1518
- a1360 a051c a1728 a0fc4 92b6c 9242e 3 usrxcvsub.c0or0 0
- a1ddc a02e0 a1964 a190c 92834 90668 11 usr.MC68010nd.o 0
- a16d0 a1360 a138c a0de0 95070 92b6c 5 spool.heds40.os 0
- a17d8 a1ddc a117c a1200 96962 92766 3 ucbf.hub.cld.av 0
- a0a9c a16d0 a0860 a0390 93c52 97be4 7 nlist.oa1.c.old 0
- a10cc a17d8 a030c a1d00 95a18 92dd6 2 ldrace.h.c30rc1 0
- a0cd8 a0a9c a1bcc a093c 92c3a 95476 6 time.hh0p@svc.2 0
- .../...
- .fi\}
- .PP
- Example 4
- .PP
- The next command will show you how to use indirection. On BSD systems, the
- variable '_file' is not the beginning of the file table, but a pointer to
- the table. It will also show you how to follow a pointer inside a structure,
- in this case, the 'ucred' pointer.
- .PP
- .nf
- nlist -a -s 0 -f7x -h 1 -l 10 \\
- '^. 1 + : " #" %3d' \\
- '_file!' \\ <== 3
- '&+1 ! #-1' \\ <== 4
- '>26 : flag %4o' \\ <== 5
- '|2 : type %4x' \\
- '|2 : count %6d' \\
- '|2 : msgcount %6d' \\
- ' : fops' \\
- ' : fdata' \\
- ' : offset %6x' \\
- ' : cred' \\
- '&. = #-1 |2 : Crref %5d' \\ <== 13
- '|2 : Uid %4d' \\
- '|2 : Gid %4d'
- .fi
- .PP
- Description of arguments not yet explained:
- .PP
- Line 3: The variable '_file' is read but the cell is not displayed because
- of the trailing '!'.
- .PP
- Line 4: Set the read-address of the cell on the right to the value read in the
- preceding cell.
- .PP
- Line 5: This cell's read-address has been initialized by the preceding cell.
- On the next pass, it will be incremented by 26 bytes (the size of the file
- structure).
- .PP
- Line 13: Here, we follow the the 'ucred' pointer and display the first
- element from that structure. The next 2 cell will auto-increment from
- that new address.
- .PP
- Here is the file table:
- .PP
- .if t \{\
- .TS
- rrrrrrrrrrrr.
- # flag type count msgcou fops fdata offset cred Crref Uid Gid
- 1 1 1 0 0 7a0f8 970a0 9e2 1047d0 5 110 100
- 2 1 1 0 0 7a0f8 93ebc 29b 1047d0 5 110 100
- 3 1 1 0 0 7a0f8 2183ac 1047d6 1047d0 5 110 100
- 4 1 1 0 0 7a0f8 94c6a 80a7c 1047d0 5 110 100
- 5 1 1 0 0 7a0f8 94c6a 8a6a4 1047d0 5 110 100
- 6 3 2 0 0 799fc 0 0 110b24 97 0 0
- 7 2 1 0 0 7a0f8 93ebc 29b 1047d0 5 110 100
- .../...
- .TE\}
- .if n \{\
- .nf
- # flag type count msgcou fops fdata offset cred Crref Uid Gid
- 1 1 1 0 0 7a0f8 970a0 9e2 1047d0 5 110 100
- 2 1 1 0 0 7a0f8 93ebc 29b 1047d0 5 110 100
- 3 1 1 0 0 7a0f8 2183ac 1047d6 1047d0 5 110 100
- 4 1 1 0 0 7a0f8 94c6a 80a7c 1047d0 5 110 100
- 5 1 1 0 0 7a0f8 94c6a 8a6a4 1047d0 5 110 100
- 6 3 2 0 0 799fc 0 0 110b24 97 0 0
- 7 2 1 0 0 7a0f8 93ebc 29b 1047d0 5 110 100
- .../...
- .fi\}
- .PP
- Example 5:
- .PP
- Dump the mount table on a SYSV.3 88K Motorola system ('dev_t' is a long on
- that system):
- .PP
- .nf
- nlist -ap -s 0 -f8x -l 4 \\
- '^. 1 +: #%2d' \\
- '_mount |2 >36 : Flags %6o' \\
- '|2 : Type %4d' \\
- ' : Bsize %5o' \\
- ' : Dev %6o' \\
- ' : Bufp' \\
- ' : Inop' \\
- ' : Mountp' \\
- '|2 : Rflags' \\
- ' : Namep' \\
- ' : Bcount %6d'
- .fi
- .PP
- Example 6:
- .PP
- This will do what 'sar -s' does, on SYSV:
- .PP
- .nf
- echo "`uname -a` `date +%D`\\n"
-
- nlist -xat -f7d -s 1 -h1 \\
- '@sysinfo' \\
- '@' \\
- '@' \\
- '@' \\
- '@#. = #1 ^1 -' \\
- '@#. = #2 ^2 -' \\
- '@#. = #3 ^3 -' \\
- '@#. = #4 ^4 -' \\
- '@#-1 #-2 #-3 #-4 +++' \\
- '#6 100 * #-1 /: "%usr"' \\
- '#7 100 * #-2 /: "%sys"' \\
- '#8 100 * #-3 /: "%wio"' \\
- '#5 100 * #-4 /: "%idle"'
- .fi
- .PP
- Finally, an example of the neat things you can do with
- .B nlist:
- .PP
- .nf
- nlist -h 1 -f 12u -l 31 -s 0 '^+1 ! 1' '^2 2 *:"Powers of 2"'
- .fi
- .SH FILES
- /unix or /vmunix name list
- .br
- /dev/kmem kernel memory
- .SH BUGS
- Conditional evaluation is very basic.
- .PP
- The syntax is not exactly user-friendly.
- .SH AUTHOR
- Chris Bertin.
- SHAR_EOF
- fi
- if test -f 'nlist.c'
- then
- echo shar: "will not over-write existing file 'nlist.c'"
- else
- cat << \SHAR_EOF > 'nlist.c'
- #ifndef lint
- static char ID[] = "@(#)nlist.c 2.1 Copyright (C) 1989 Chris Bertin 89/07/31";
- #endif
- /*
- * nlist -- display and monitor kernel variables. Dump kernel structures.
- *
- * This program is free for redistribution as long as this header
- * remains unchanged.
- *
- * Copyleft Chris Bertin, July 1989
- *
- */
- #include <stdio.h>
- #ifdef V7
- #include <a.out.h>
- #else
- #include <nlist.h>
- #endif /* V7 */
- #ifdef SYSV
- #include <string.h>
- #else
- #include <strings.h>
- #endif /* SYSV */
- #include <ctype.h>
- #include <memory.h>
- #include <time.h>
- #include <sys/types.h>
- #include <sys/signal.h>
- #ifdef SYSV
- #include <sys/var.h>
- #endif
-
- #define NLISTBUG /* see comment in fixnlist() */
-
- #ifndef SYSV
- #define DEF_NLIST "/vmunix" /* default namelist */
- #else
- #define DEF_NLIST "/unix"
- #endif
- #define DEF_KMEM "/dev/kmem" /* default memory device */
- #define DEF_SLEEP 1 /* default pause between displays */
- #define DEF_WIDTH 8 /* default print width */
- #define DEF_LOOPS -1 /* default number of loops (infinite) */
- #define DEF_RDSIZE 4 /* default read size */
-
- /* misc return values */
- #define R_OK 0 /* OK */
- #define R_NOPRINT 1 /* value was computed but don't print */
- #define R_FLOAT 2 /* print value in float format */
- #define R_SKIP 3 /* skip this entry */
- #define R_ERR -1 /* print error value */
-
- /* misc */
- #define CDEPTH 4 /* max number of push for formulas */
- #define NDEC 2 /* number of decimals for float */
- #define NSPACES 1 /* number of spaces between fields */
-
- /* header special characters */
- #define H_NOPRINT '@' /* don't print if first character */
- #define H_POST ':' /* real header start character */
- #define H_SET '=' /* set field to value */
- #define H_INIT '!' /* initialize field to value */
- #define H_SIZE '|' /* read size (real symbols only) */
- #define H_FMT '%' /* field print width */
- #define H_INCR '>' /* increment address on next loop */
- #define H_NONZERO '?' /* quit if this address is 0 */
-
- /* field identifiers in formulas. (For example: #1: value of field1, */
- /* ^+1: previous value of next field, &.: nlist address in current field) */
- #define H_CURVAL '#' /* current value in field number */
- #define H_PREVAL '^' /* previous value in field number */
- #define H_ADDR '&' /* the nlist address of the field */
- #define H_CURFIELD '.' /* current field */
-
- /* values for -h flag */
- #define HD_NONE 0 /* don't print header */
- #define HD_ONCE 1 /* print header once only */
- #define HD_PAGE 2 /* print header every $LINES lines */
-
- typedef float val_t;
- typedef struct nlist nl_t;
-
- typedef struct field {
- nl_t *f_nl; /* nlist entry pointer */
- char *f_arg; /* original argument */
- char *f_form; /* formula or symbol */
- char *f_post; /* title */
- char *f_fmt; /* print format (dec, oct, hex...) */
- char *f_buf; /* read buffer for string printf's */
- short f_flags; /* features */
- short f_width; /* print width */
- short f_rdsize; /* read size */
- off_t f_offset; /* address offset */
- off_t f_incr; /* address increment */
- val_t f_curval; /* current value */
- val_t f_preval; /* previous value */
- } fld_t;
-
- /* f_flags bits */
- #define F_TITLE 0x1 /* Title is present */
- #define F_SYM 0x2 /* valid symbol */
- #define F_SET 0x4 /* set value */
- #define F_INIT 0x8 /* set value once only */
- #define F_DONE 0x10 /* init done */
- #define F_QUOTED 0x20 /* header is quoted. Don't clean it */
- #define F_NONZERO 0x40 /* quit if address is 0 */
- #define F_TIME 0x80 /* print the value as date/time */
- #define F_READOK 0x100 /* OK to read size other that 1,2,4 */
-
- extern char *optarg, *getenv(), *parsearg(), *alloc(), *calloc();
- extern char *prfmt(), *spaces(), *cleanbuf();
- extern char *sys_errlist[];
- extern int errno, optind;
- extern double ceil();
-
- /* formats */
- char decfmt[] = "%*d"; /* decimal print mode */
- char unsfmt[] = "%*u"; /* unsigned decimal print mode */
- char octfmt[] = "%*o"; /* octal print mode */
- char hexfmt[] = "%*x"; /* hex print mode */
- char flofmt[] = "%*.*f"; /* floating point format */
- char strfmt[] = "%*.*s"; /* string print format */
- #ifndef V7
- char extoctfmt[] = "%#*o"; /* hex with '0' prefix */
- char exthexfmt[] = "%#*x"; /* octal with '0x' prefix */
- #endif
- #define DEF_FMT hexfmt /* default print format */
-
- val_t calc[CDEPTH]; /* calculator stack */
- int cdepth; /* calculator stack depth */
-
- int tim, uniq, fmtprefix, debug, autoincr; /* flags with default 0 */
- int strict = 1; /* flags with default 1 */
- char *buf, *hdr; /* line and header buffers */
- char *pname; /* argv[0], for error messages */
-
- char *kmemf = DEF_KMEM;
- char *nlistf = DEF_NLIST;
- char *fmt = DEF_FMT;
- int slp = DEF_SLEEP;
- int width = DEF_WIDTH;
- int nloops = DEF_LOOPS;
- int header = HD_PAGE;
-
- main (argc, argv)
- char **argv;
- {
- register int mem, i;
- int nsymbols, maxw, prtime;
- register fld_t *baseflp, *flp;
- nl_t *nl;
- char *p;
- int onfpe();
-
- pname = *argv;
- while ((i = getopt(argc, argv, "aD:f:h:l:m:n:ps:tux")) != -1) {
- switch (i) {
- case 'a':
- autoincr++;
- break;
- case 'D':
- debug = stoi(&optarg, "debug level", 0, 0);;
- break;
- case 'f':
- fmt = prfmt(&optarg, &width, &prtime, 0, optarg);
- break;
- case 'h':
- header = stoi(&optarg, "header value", 1, 0);
- break;
- case 'l':
- nloops = stoi(&optarg, "number of loops", 0, 0);
- break;
- case 'm':
- kmemf = optarg;
- break;
- case 'n':
- nlistf = optarg;
- break;
- case 'p':
- fmtprefix++;
- break;
- case 's':
- slp = stoi(&optarg, "sleep time", 0, 0);
- break;
- case 't':
- tim++;
- break;
- case 'u':
- uniq++;
- break;
- case 'x':
- strict = 0;
- break;
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
- if (argc <= 0)
- usage();
- if ((mem = open (kmemf, 0)) < 0)
- perrexit (kmemf);
- baseflp = (fld_t *) alloc((int) (argc * sizeof (fld_t)));
- nl = (nl_t *) alloc((int) ((argc + 2) * sizeof (nl_t)));
- for (flp = baseflp, maxw = nsymbols = 0, i = 0; i < argc; i++, flp++) {
- p = parsearg(flp, *(argv + i));
- if (flp->f_fmt != NULL)
- maxw += flp->f_width + NSPACES;
- if (flp->f_flags & F_SYM) {
- flp->f_nl = nl + nsymbols;
- nsymbols++;
- #ifdef V7
- (void) strncpy(flp->f_nl->n_name, p, SYMLENGTH);
- #else
- flp->f_nl->n_name = p;
- #endif
- continue;
- }
- if (autoincr && i > 0 && flp->f_incr == 0 && *p == '\0') {
- sprintf(p = alloc(32), "%c%c%c%c-1 %d +", H_ADDR,
- H_CURFIELD, H_SET, H_ADDR, (flp - 1)->f_rdsize);
- flp->f_flags |= F_SET;
- }
- flp->f_nl = nl + (argc - i + nsymbols + 1);
- flp->f_form = p;
- }
- if (maxw == 0) {
- fprintf(stderr, "%s: nothing to print\n", pname);
- exit (1);
- }
- if (nsymbols) {
- donlist(nl, mem, nsymbols);
- for (i = 0, flp = baseflp; i < argc; i++, flp++)
- if (flp->f_offset && flp->f_nl->n_value)
- flp->f_nl->n_value += flp->f_offset;
- }
- if (header != HD_NONE) {
- hdr = alloc(maxw);
- for (p = hdr, i = 0, flp = baseflp; i < argc; i++, flp++) {
- if (flp->f_fmt == NULL)
- continue;
- sprintf(p, "%s%*.*s", spaces(NSPACES), flp->f_width,
- flp->f_width, flp->f_post? flp->f_post: flp->f_arg);
- p += flp->f_width + NSPACES;
- }
- }
- (void) signal(SIGFPE, onfpe);
- for (;;) {
- if (process(baseflp, argc, mem, maxw, prtime)) {
- outputline();
- if (--nloops == 0)
- break;
- }
- (void) sleep((unsigned) slp);
- }
- return (0);
- }
-
- /*
- * Process the arguments once. Return 1 if 'buf' is to be printed.
- */
- process(baseflp, max, mem, maxw, prtime)
- register fld_t *baseflp;
- register int max, mem, maxw;
- {
- register int i;
- register char *p;
- register fld_t *flp;
- static char *lastbuf, *tmp;
-
- if (buf == NULL) {
- buf = alloc(maxw);
- lastbuf = alloc(maxw);
- tmp = alloc(BUFSIZ);
- }
- for (flp = baseflp, buf[0] = '\0', i = 0; i < max; i++, flp++) {
- tmp[0] = '\0';
- switch (analyze(baseflp, flp, max, mem)) {
- case R_NOPRINT:
- continue;
- case R_SKIP:
- sprintf(tmp, strfmt, flp->f_width, flp->f_width,
- "--------------------");
- break;
- case R_FLOAT:
- sprintf(tmp, flofmt, flp->f_width, NDEC, flp->f_curval);
- break;
- case R_OK:
- p = flp->f_fmt;
- if (p == strfmt) {
- if (prtime || (flp->f_flags & F_TIME)) {
- time_t t = (time_t) flp->f_curval;
- (void) strncpy(flp->f_buf, ctime(&t),
- flp->f_width);
- }
- sprintf(tmp, strfmt, flp->f_width, flp->f_width,
- cleanbuf(flp->f_buf, flp->f_width));
- break;
- }
- #ifndef V7
- if (fmtprefix && (long) flp->f_curval) {
- if (flp->f_fmt == hexfmt)
- p = exthexfmt;
- else if (flp->f_fmt == octfmt)
- p = extoctfmt;
- }
- #endif
- sprintf(tmp, p, flp->f_width, (long) flp->f_curval);
- break;
- case R_ERR:
- if (strict) {
- outputline();
- fprintf(stderr, "%s: symbol '%s' not found\n",
- pname, flp->f_nl->n_name);
- exit (1);
- }
- sprintf(tmp, strfmt, flp->f_width, flp->f_width,
- "????????????????????");
- break;
- }
- if (strlen(tmp) > flp->f_width) {
- if (strict) {
- outputline();
- fprintf(stderr, "%s: print overflow\n", pname);
- exit (1);
- }
- sprintf(tmp, strfmt, flp->f_width, flp->f_width,
- "********************");
- }
- (void) strcat(buf, spaces(NSPACES));
- (void) strcat(buf, tmp);
- }
- for (i = 0, flp = baseflp; i < max; i++, flp++) {
- flp->f_preval = flp->f_curval;
- if (flp->f_incr && flp->f_nl->n_value)
- flp->f_nl->n_value += flp->f_incr;
- }
- if (uniq) {
- if (strcmp(buf, lastbuf) == NULL)
- return (0);
- (void) strcpy(lastbuf, buf);
- }
- return(1);
- }
-
- /*
- * Print output buffer, adding title if needed. Exit if err is set.
- */
- outputline()
- {
- static int lines, nlines;
- char *p;
-
- if (buf == NULL || *buf == '\0')
- return;
- if (header != HD_NONE) {
- if (nlines == 0)
- lines = nlines = (p = getenv("LINES"))? atoi(p): 24;
- if (lines == nlines) {
- printline(hdr);
- lines = 2;
- }
- lines++;
- if (header == HD_ONCE)
- header = HD_NONE;
- }
- printline(buf);
- }
-
- /*
- * Print a line, with the current time if -t flag present.
- */
- printline(line)
- char *line;
- {
- time_t t;
- register struct tm *tm;
-
- if (tim) {
- (void) time(&t);
- tm = localtime(&t);
- printf("%2d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec);
- }
- printf("%s\n", line);
- fflush(stdout);
- }
-
- /*
- * Parse an argument and initialize the control structure. Return a pointer
- * to a symbol without any trailers, if the argument is a symbol name.
- */
- char *
- parsearg(flp, str)
- register fld_t *flp;
- char *str;
- {
- char *p;
- register char *pp, *xp;
- register char c;
- int endsym, w, prtime;
-
- flp->f_rdsize = DEF_RDSIZE;
- flp->f_width = width;
- flp->f_fmt = fmt;
- (void) skipspaces(&str);
- if (*str == H_NOPRINT) {
- flp->f_fmt = NULL;
- str++;
- (void) skipspaces(&str);
- }
- if (isalpha(*str) || *str == '_')
- flp->f_flags |= F_SYM;
- flp->f_arg = str;
- (void) strcpy(pp = alloc(strlen(str) + 1), str);
- for (endsym = 0, p = pp; *p; ) {
- (void) skipspaces(&p);
- xp = p;
- switch (*p++) {
- case H_POST:
- endsym++;
- (void) skipspaces(&p);
- if ((c = *p) != '\'' && c != '"') {
- flp->f_post = p;
- break;
- }
- flp->f_post = ++p;
- flp->f_flags |= F_QUOTED;
- while (*p != c)
- if (*p++ == '\0') {
- fprintf(stderr,
- "%s: missing quote in header -- %s\n",
- pname, pp);
- exit (1);
- }
- *p++ = '\0';
- break;
- case H_FMT:
- endsym++;
- flp->f_fmt = prfmt(&p, &w, &prtime, 1, flp->f_arg);
- if (w)
- flp->f_width = w;
- if (flp->f_fmt == strfmt) {
- flp->f_buf = alloc(flp->f_width + 1);
- if (prtime)
- flp->f_flags |= F_TIME;
- else
- flp->f_flags |= F_READOK;
- }
- break;
- case H_SIZE:
- endsym++;
- flp->f_rdsize = stoi(&p, "read size", 0, 1);
- break;
- case H_INCR:
- endsym++;
- flp->f_incr = stoi(&p, "increment value", 1, 1);
- break;
- case H_SET:
- flp->f_flags |= F_SET;
- break;
- case H_INIT:
- *(p - 1) = (flp->f_flags & F_SYM)? '\0': H_SET;
- flp->f_flags |= (F_SET|F_INIT);
- flp->f_fmt = NULL;
- break;
- case '+':
- case '-':
- if (flp->f_flags & F_SYM)
- endsym++;
- --p;
- flp->f_offset = (val_t) stoi(&p, "offset", 1, 1);
- break;
- case H_NONZERO:
- endsym++;
- flp->f_flags |= F_NONZERO;
- break;
- default:
- continue;
- }
- if (! endsym)
- continue;
- *xp = '\0';
- }
- if (flp->f_buf == NULL)
- flp->f_buf = alloc(flp->f_rdsize);
- if ((flp->f_flags & F_QUOTED) == 0)
- cleanspaces(flp->f_post);
- cleanspaces(pp);
- cleanspaces(flp->f_arg);
- return (pp);
- }
-
- /*
- * Handle symbols, formulas, reads, calculator, etc...
- */
- analyze(baseflp, flp, max, mem)
- register fld_t *baseflp, *flp;
- register int max, mem;
- {
- fld_t *nfp;
- char *p, *form, *fmtp;
- register int i;
- register val_t *vp;
- int prev, addr, seta;
- static int skiptonext;
-
- if (flp == baseflp)
- skiptonext = 0;
- if (debug > 1)
- showfl(flp, flp - baseflp, "start analyze");
- if (flp->f_flags & F_DONE)
- return (R_NOPRINT);
- if (flp->f_flags & F_INIT)
- flp->f_flags |= F_DONE;
- prev = addr = seta = 0;
- fmtp = flp->f_fmt;
- p = form = flp->f_form;
- if (flp->f_flags & F_SYM) {
- skiptonext = 0;
- if (flp->f_nl->n_value == 0)
- return (R_ERR);
- flp->f_curval = (val_t) doread(flp->f_nl->n_name, kmemf, mem,
- flp->f_nl->n_value, flp->f_buf, flp->f_rdsize,
- (flp->f_flags & F_READOK));
- return ((fmtp == flofmt)? R_FLOAT: (fmtp? R_OK: R_NOPRINT));
- }
- for (i = 0; i < CDEPTH; i++)
- calc[i] = 0;
- cdepth = 0;
- vp = &flp->f_curval;
- if (flp->f_flags & F_SET) {
- nfp = baseflp + fn(baseflp, flp, &p, &prev, &seta, max, 0) - 1;
- if (seta == 0) {
- flp = nfp;
- vp = prev? &flp->f_preval: &flp->f_curval;
- }
- (void) skipspaces(&p);
- if (*p++ != H_SET)
- badf(form, --p, "invalid 'set' format");
- }
- *vp = 0;
- while (*p) {
- if (skipspaces(&p))
- continue;
- if (i = isdigit(*p))
- *vp = stoi(&p, "formula", 1, 1);
- else if (i = fn(baseflp, flp, &p, &prev, &addr, max, 1)) {
- if (addr)
- *vp = (val_t) (baseflp + i - 1)->f_nl->n_value;
- else
- *vp = (prev? (baseflp + i - 1)->f_preval:
- (baseflp + i - 1)->f_curval);
- }
- if (i) {
- if (push(*vp) == R_ERR)
- badf(form, p, "stack overflow");
- *vp = 0;
- continue;
- }
- switch (*p++) {
- case '+':
- calc[1] = calc[1] + calc[0];
- break;
- case '-':
- calc[1] = calc[1] - calc[0];
- break;
- case '*':
- calc[1] = calc[1] * calc[0];
- break;
- case '/':
- if (calc[0] != 0)
- calc[1] = calc[1] / calc[0];
- else if (strict)
- badf(form, --p, "zero divide");
- else
- return (R_ERR);
- break;
- default:
- badf(form, --p, "invalid operand");
- }
- *vp = 0;
- if (pop() == R_ERR)
- badf(form, --p, "stack empty");
- }
- if (*vp == 0)
- *vp = calc[0];
- if (seta)
- nfp->f_nl->n_value = (long) *vp;
- if (debug > 2)
- showfl(flp, flp - baseflp, "end analyze");
- if ((flp->f_flags & F_NONZERO) && flp->f_nl->n_value == 0)
- skiptonext++;
- if (skiptonext)
- return (fmtp? R_SKIP: R_NOPRINT);
- if (flp->f_nl->n_value)
- flp->f_curval = (val_t) doread(flp->f_nl->n_name, kmemf, mem,
- flp->f_nl->n_value, flp->f_buf, flp->f_rdsize,
- (flp->f_flags & F_READOK));
- if (fmtp == flofmt || (fmtp == decfmt &&
- (val_t) ceil((double) flp->f_curval) != flp->f_curval))
- return (R_FLOAT);
- return (fmtp? R_OK: R_NOPRINT);
- }
-
- /*
- * Return field number. Set 'prev' and 'addr' flags, advance formula pointer.
- */
- fn(baseflp, flp, p, prev, addr, max, errok)
- register fld_t *baseflp, *flp;
- register char **p;
- int *prev, *addr;
- {
- register int id, plus;
-
- if (((*addr = (**p == H_ADDR)) == 0) &&
- ((*prev = (**p == H_PREVAL)) == 0) && **p != H_CURVAL) {
- if (errok)
- return (0);
- badf(flp->f_form, *p, "not a field identifier");
- }
- (*p)++;
- if (**p == H_CURFIELD) {
- (*p)++;
- return ((flp - baseflp) + 1);
- }
- plus = (**p == '+');
- if ((id = stoi(p, "field number", 1, 1)) < 0 || (plus && id > 0))
- id = (int) (flp - baseflp) + 1 + id;
- if (id <= 0 || id > max) {
- char *pp;
- sprintf(pp = alloc((id / 10) + 2), "%d", id);
- badf(flp->f_form, pp, "invalid field number");
- }
- return (id);
- }
-
- /*
- * Convert a string into a positive or negative int. Handles hex and octal.
- * Advance pointer.
- */
- stoi(p, what, negok, errok)
- char *what;
- register char **p;
- {
- int n, newval, neg, base;
-
- neg = 0;
- base = 10;
- (void) skipspaces(p);
- if (**p == '+' || (negok && (neg = (**p == '-'))))
- (*p)++;
- if (! strncmp(*p, "0x", 2)) {
- base = 16;
- (*p) += 2;
- }
- else if (**p == '0') {
- base = 8;
- (*p)++;
- }
- for (newval = 0; **p; (*p)++) {
- if ((n = conv(*p, base, what, errok)) < 0)
- break;
- newval = (newval * base) + n;
- }
- (void) skipspaces(p);
- return (neg? -newval: newval);
- }
-
- /*
- * Convert an ascii character into a digit.
- */
- conv(p, base, what, errok)
- char *p, *what;
- {
- register char c;
-
- if (isdigit(c = *p))
- return (c - '0');
- if (isupper(c))
- c = tolower(c);
- if (base == 16 && c >= 'a' && c <= 'f')
- return (10 + c - 'a');
- if (errok)
- return (-1);
- fprintf(stderr, "%s: illegal %s (%s)\n", pname, what, p);
- usage();
- /* NOTREACHED */
- }
-
- /*
- * Advance pointer to next non-space character. Return 1 pointer changed.
- */
- skipspaces(p)
- register char **p;
- {
- if (! isspace(**p))
- return (0);
- while (isspace(**p))
- (*p)++;
- return (1);
- }
-
- /*
- * Remove trailing spaces from string.
- */
- cleanspaces(str)
- register char *str;
- {
- if (str == NULL || *str == '\0')
- return;
- while (*str)
- str++;
- --str;
- while (isspace(*str))
- *str-- = '\0';
- }
-
- /*
- * Replace unprintable characters in a buffer by dots ('.').
- */
- char *
- cleanbuf(p, n)
- register char *p;
- {
- register char *pp;
-
- for (pp = p; --n >= 0; pp++)
- if (! isprint(*pp))
- *pp = '.';
- return (p);
- }
-
- /*
- * Handle a format string. Return a format pointer and the width in 'width'.
- * Advance pointer.
- */
- char *
- prfmt(p, w, prtime, errok, str)
- char **p;
- char *str;
- int *w, *prtime;
- {
- *prtime = 0;
- if ((*w = stoi(p, "print width", 0, 1)) == 0)
- *w = DEF_WIDTH;
- switch (**p) {
- case 'd':
- return (decfmt);
- case 'f':
- return (flofmt);
- case 'o':
- return (octfmt);
- case 't':
- *prtime = 1;
- /* fall thru */
- case 's':
- return (strfmt);
- case 'u':
- return (unsfmt);
- case 'x':
- return (hexfmt);
- }
- if (! isalpha(**p) && errok) {
- (*p)++;
- return (DEF_FMT);
- }
- fprintf(stderr, "%s: invalid print format in '%s' (%c)\n", pname,
- str, **p);
- outputline();
- exit (1);
- /* NOTREACHED */
- }
-
- /*
- * Push argument onto calculator stack.
- */
- push(n)
- register val_t n;
- {
- register int i;
-
- if (cdepth++ == CDEPTH)
- return (R_ERR);
- for (i = cdepth; --i >= 0; )
- calc[i] = i? calc[i - 1]: n;
- return (R_OK);
- }
-
- /*
- * Pop one argument from calculator stack.
- */
- pop()
- {
- register int i;
-
- if (--cdepth <= 0)
- return (R_ERR);
- for (i = 1; i <= cdepth; i++)
- if ((calc[i - 1] = calc[i]) == 0)
- break;
- return (R_OK);
- }
-
- /*
- * Do 'nlist' and validate name list. Validation is very basic. Note that
- * one extra 'nlist' entry was allocated to handle the additional symbol.
- */
- donlist(nl, mem, max)
- register nl_t *nl;
- {
- char *p;
- int nproc, size;
- #ifdef SYSV
- struct var v;
-
- #ifdef UNDERSCORESYM
- (nl + max)->n_name = "_v";
- #else
- (nl + max)->n_name = "v";
- #endif
- p = (char *) &v;
- size = sizeof (v);
- #else /* SYSV */
- #ifdef V7
- strncpy((nl + max)->n_name, "_nproc", SYMLENGTH);
- #else
- #ifdef UNDERSCORESYM
- (nl + max)->n_name = "_nproc";
- #else
- (nl + max)->n_name = "nproc";
- #endif
- #endif /* V7 */
- p = (char *) &nproc;
- size = sizeof nproc;
- #endif /* SYSV */
- if (nlist (nlistf, nl) < 0) {
- fprintf(stderr, "%s: nlist(%s) failed -- ", pname, nlistf);
- perrexit("");
- }
- if ((nl + max)->n_value == 0) {
- fprintf(stderr, "%s: symbol '%s' not found in %s\n", pname,
- (nl + max)->n_name, nlistf);
- exit (1);
- }
- (void) doread((nl + max)->n_name, kmemf, mem,
- (off_t) (nl + max)->n_value, p, size, 1);
- #ifdef SYSV
- nproc = v.v_proc;
- #endif
- if (nproc > 4096 || nproc < 3) {
- fprintf(stderr, "Namelist out of date\n");
- exit (1);
- }
- #ifdef NLISTBUG
- fixnlist(nl, max);
- #endif
- }
-
- #ifdef NLISTBUG
- /*
- * If a symbol is more than once in the list, all but the first one will have
- * an n_value of zero. This normally doesn't matter, but 'nlist' can ask for
- * symbol+4 and symbol+8, for example, in which case the second one fails.
- * This is a bug present in all the nlist(3) I have tried.
- */
- fixnlist(nl, max)
- register nl_t *nl;
- register int max;
- {
- register nl_t *np, *npp;
-
- for (np = nl; np < nl + (max - 1) ; np++)
- for (npp = np + 1; npp < nl + max; npp++)
- if (! strcmp(npp->n_name, np->n_name)) {
- npp->n_value = np->n_value;
- break;
- }
- }
- #endif /* NLISTBUG */
-
- /*
- * Generic read routine. If read size is 1, 2, 4 bytes, return that value,
- * else return 0. If okdiff is 0, don't allow read sizes != 1, 2, 4.
- */
- doread(what, from, mem, offset, into, size, okdiff)
- char *what, *from, *into;
- off_t offset;
- {
- if (debug)
- showread(what, from, offset, size, -1);
- (void) lseek(mem, offset, 0);
- if (read(mem, into, (unsigned) size) != size) {
- showread(what, from, offset, size, errno);
- if (strict) {
- outputline();
- exit (1);
- }
- }
- switch (size) {
- case sizeof (char):
- return ((int) *into);
- case sizeof (short):
- return ((int) *(short *) into);
- case sizeof (int):
- return ((int) *(int *) into);
- default:
- if (okdiff)
- return (0);
- outputline();
- fprintf(stderr, "%s: Invalid read size: %d\n", pname, size);
- exit (1);
- }
- /* NOTREACHED */
- }
-
- /*
- * Debug and error routine. Show read arguments.
- */
- showread(what, from, offset, size, err)
- char *what, *from;
- off_t offset;
- {
- fprintf(stderr, "%s: read ", pname);
- if (what)
- fprintf(stderr, "'%s', ", what);
- fprintf(stderr, "%d bytes @ offset 0x%x in %s", size, offset, from);
- if (err >= 0)
- fprintf(stderr, " -- %s", sys_errlist[err]);
- fprintf(stderr, "\n");
- }
-
- /*
- * Debug routine. Show the whole control structure.
- */
- showfl(flp, n, str)
- register fld_t *flp;
- char *str;
- {
- fprintf(stderr, " %s: fld %d, nl %x, buf '%s', name '%s', addr %x\n",
- str, n, flp->f_nl, flp->f_buf, flp->f_nl->n_name,
- flp->f_nl->n_value);
- fprintf(stderr, " arg '%s', form '%s', post '%s', fmt '%s'\n",
- flp->f_arg, flp->f_form, flp->f_post, flp->f_fmt);
- fprintf(stderr, " f 0x%x, w %d, rd %d, o %d, i %d, cur %d, pre %d\n",
- flp->f_flags, flp->f_width, flp->f_rdsize, flp->f_offset,
- flp->f_incr, (long) flp->f_curval, (long) flp->f_preval);
- }
-
- /*
- * Allocate 'n' bytes on the heap.
- */
- char *
- alloc(n)
- {
- char *a;
-
- if ((a = calloc((unsigned) n, (unsigned) 1)) == 0)
- perrexit("calloc");
- return (a);
- }
-
- /*
- * Build an array of spaces, return the address.
- */
- char *
- spaces(n)
- {
- static char *sp;
- register char *p;
-
- if (sp == NULL) {
- sp = alloc(n + 1);
- for (p = sp; --n >= 0; p++)
- *p = ' ';
- }
- return (sp);
- }
-
- badf(form, msg1, msg2)
- char *form, *msg1, *msg2;
- {
- outputline();
- fprintf(stderr, "%s: invalid formula '%s'", pname, form);
- if (msg1 && *msg1)
- fprintf(stderr, " (%s)", msg1);
- if (msg2 && *msg2)
- fprintf(stderr, " -- %s", msg2);
- fprintf(stderr, "\n");
- exit (1);
- }
-
- perrexit(str)
- char *str;
- {
- perror(str);
- exit (1);
- }
-
- /*ARGSUSED*/
- onfpe(n)
- int n;
- {
- outputline();
- fprintf(stderr, "%s: Floating poing exception\n", pname);
- exit (1);
- }
-
- usage()
- {
- fprintf(stderr, "Usage: %s [-aptux] [-f format] [-h header] [-l loops] [-m mem]\n\t[-n namelist] [-s sleep] [-D debug] symbol|formula...\n", pname);
- exit (1);
- }
- SHAR_EOF
- fi
- if test -f 'Makefile'
- then
- echo shar: "will not over-write existing file 'Makefile'"
- else
- cat << \SHAR_EOF > 'Makefile'
- # Makefile for nlist
-
- all: nlist man
-
- nlist: nlist.o
- $(CC) $(LDFLAGS) -o $@ $@.o -lm
-
- clean:
- rm -f core *.o
-
- clobber: clean
- rm -f nlist
-
- man:
- tbl < nlist.8 | nroff -man > nlist.man
- SHAR_EOF
- fi
- if test -f 'chars.sun'
- then
- echo shar: "will not over-write existing file 'chars.sun'"
- else
- cat << \SHAR_EOF > 'chars.sun'
- #! /bin/sh
-
- echo "Showing character I/O statistics"
-
- nlist -t -s 2 -f9d \
- '_tk_nin : "Chars in"' \
- '_tk_nout : "Chars out"' \
- '#. = #1 #2 + : Total' \
- '#1 100 * #3 / : "% Input"' \
- '#2 100 * #3 / : "% Output"'
- SHAR_EOF
- fi
- if test -f 'config.sh'
- then
- echo shar: "will not over-write existing file 'config.sh'"
- else
- cat << \SHAR_EOF > 'config.sh'
- #! /bin/sh
-
- echo "Checking configuration and building 'nlist'"
-
- CFLAGS="-O"
- if [ -f /unix ]; then
- echo "This looks like a System 5 system"
- CFLAGS="${CFLAGS} -DSYSV"
- NAMELIST=/unix
- getmain() grep -c '_main[ ]'
- elif [ -f /vmunix ]; then
- echo "This looks like a BSD system"
- NAMELIST=/vmunix
- getmain() grep -c '_main$'
- else
- echo "No /unix and no /vmunix. What system are you?" >&2
- exit 1
- fi
-
- if [ `nm ${NAMELIST} | getmain` -gt 0 ]; then
- CFLAGS="${CFLAGS} -DUNDERSCORESYM"
- MSG=prepends
- else
- MSG="doesn't prepend"
- fi
-
- echo "It looks like the loader ${MSG} an underscore to symbol names"
- echo "If this is not right, 'nlist' may fail. Build it manually"
-
- echo ""
- echo "Making 'nlist'"
-
- make nlist CFLAGS="${CFLAGS}"
- SHAR_EOF
- fi
- if test -f 'dnlc.sun'
- then
- echo shar: "will not over-write existing file 'dnlc.sun'"
- else
- cat << \SHAR_EOF > 'dnlc.sun'
- #! /bin/sh
-
- echo "Dumping 100 entries of the dnlc (ncache) structures,
- following the 'hash_next' pointer"
-
- nlist -ax -h1 -s 0 -f6x -l 10 \
- '_ncache : Hshnxt' \
- ' : Hshprv' \
- ' : Lrunxt' \
- ' : Lruprv' \
- ' : Vp' \
- ' : Dp' \
- '|1 : Len%3d' \
- '|15 : Name%15s' \
- ' : Ucred' \
- '@&1 = #1'
- SHAR_EOF
- fi
- if test -f 'file.sun'
- then
- echo shar: "will not over-write existing file 'file.sun'"
- else
- cat << \SHAR_EOF > 'file.sun'
- #! /bin/sh
-
- echo "Dumping 10 entries of the file table. Note that _file is the ADDRESS of
- the file table and not the file table itself"
-
- # description (lines following the 'nlist' line)
- # line 1: header
- # line 2: read '_file' once
- # line 3: set address of next field to content of previous field
- # line 4: read that and increment by 26 next time
- # line 5: read rest of structure with auto increment
-
- nlist -a -s 0 -f7x -h 1 -l 10 \
- '^. 1 + :" #" %3d' \
- '_file!' \
- '&+1!#-1' \
- '>26 : flag %4o' \
- '|2 : type %6x' \
- '|2 : count %6d' \
- '|2 : msgcount %6d' \
- ' : fops' \
- ' : fdata' \
- ' : offset %6x' \
- ' : cred' \
- '&. = #-1 |2 : Crref %5d' \
- '|2 : Uid %4u' \
- '|2 : Gid %4u'
-
- SHAR_EOF
- fi
- if test -f 'file.sys53'
- then
- echo shar: "will not over-write existing file 'file.sys53'"
- else
- cat << \SHAR_EOF > 'file.sys53'
- #! /bin/sh
-
- echo "Dumping 50 entries of the file table"
-
- nlist -ap -s 0 -fd -h 2 -l 50 \
- '^. 1 +: #%3d' \
- '_file>12|1:Flag%4o' \
- '&.=&-1 2+|2:Count%5u' \
- ':"Inode"%10x' \
- ':"Offset"%10d'
- SHAR_EOF
- fi
- if test -f 'minfo.sys5'
- then
- echo shar: "will not over-write existing file 'minfo.sys5'"
- else
- cat << \SHAR_EOF > 'minfo.sys5'
- #! /bin/sh
-
- echo "Dumping the 'minfo' structure. Unique lines only, every 2 seconds"
-
- nlist -atu -f8d -s 2 \
- 'minfo : FreeM %5d' \
- ' : FreeS %5d' \
- ' : Vflt' \
- ' : Demd' \
- ' : Swap %5d' \
- ' : Cache' \
- ' : File' \
- ' : Pfault' \
- ' : CopyWr' \
- ' : Steal' \
- ' : Freed' \
- ' : UmodS' \
- ' : UmodF'
- SHAR_EOF
- fi
- if test -f 'mount.sun'
- then
- echo shar: "will not over-write existing file 'mount.sun'"
- else
- cat << \SHAR_EOF > 'mount.sun'
- #! /bin/sh
-
- echo "Dumping 10 entries of the mount table"
-
-
- nlist -p -aa -s 0 -f 10x -l 10 \
- '^. 1 + : " #"%2d' \
- '_mounttab>28 : Vfsp' \
- ' |1 : Maj %3o' \
- ' |1 : Min %3o' \
- ' : Devvp' \
- ' : Bufp' \
- ' : Qinod' \
- ' : Qflags |2' \
- ' : Btime %6d' \
- ' : Ftime %6d'
- SHAR_EOF
- fi
- if test -f 'mount.sys53'
- then
- echo shar: "will not over-write existing file 'mount.sys53'"
- else
- cat << \SHAR_EOF > 'mount.sys53'
-
- SHAR_EOF
- fi
- if test -f 'syserr.sys5'
- then
- echo shar: "will not over-write existing file 'syserr.sys5'"
- else
- cat << \SHAR_EOF > 'syserr.sys5'
- #! /bin/sh
-
- echo "Dumping the 'syserr' structure. Unique lines only, every 2 seconds"
-
- nlist -atu -f7d -s 2 \
- 'syserr :InoOvf' \
- ' :FileOvf' \
- ' :TextOvf' \
- ' :ProcOvf' \
- ' :Silo' \
- ' :CrdRds' \
- ' :Alerts' \
- ' :Faults' \
- ' :Timeouts'
- SHAR_EOF
- fi
- if test -f 'sysinfo1.sys5'
- then
- echo shar: "will not over-write existing file 'sysinfo1.sys5'"
- else
- cat << \SHAR_EOF > 'sysinfo1.sys5'
- #! /bin/sh
-
- echo "Dumping part of the 'sysinfo' structure. Unique lines only, every 2 seconds"
-
- nlist -atu -f8d -s 2 \
- 'sysinfo :CPU_IDLE' \
- ' :CPU_USER' \
- ' :CPU_KERN' \
- ' :CPU_WAIT' \
- ' :WAIT_IO' \
- ' :WAIT_SWP' \
- ' :WAIT_PIO'
- SHAR_EOF
- fi
- if test -f 'sysinfo2.sys5'
- then
- echo shar: "will not over-write existing file 'sysinfo2.sys5'"
- else
- cat << \SHAR_EOF > 'sysinfo2.sys5'
- #! /bin/sh
-
- echo "Dumping part of the 'sysinfo' structure. Unique lines only, every 2 seconds"
-
- nlist -atu -f8d -s 2 \
- 'sysinfo+28 :Breads' \
- ' :Bwrites' \
- ' :Lreads' \
- ' :Lwrites' \
- ' :Phreads' \
- ' :Phwrites' \
- ' :Swapin' \
- ' :Swapout' \
- ' :Bswapin' \
- ' :Bswapout'
- SHAR_EOF
- fi
- if test -f 'sysinfo3.sys5'
- then
- echo shar: "will not over-write existing file 'sysinfo3.sys5'"
- else
- cat << \SHAR_EOF > 'sysinfo3.sys5'
- #! /bin/sh
-
- echo "Dumping part of the 'sysinfo' structure. Unique lines only, every 2 seconds"
-
- nlist -atu -f8d -s 2 \
- 'sysinfo+68 :PSwtches' \
- ' :Syscall' \
- ' :SReads' \
- ' :SWrites' \
- ' :SForks %6d' \
- ' :SExecs %6d' \
- ' :RunQ' \
- ' :RunOcc' \
- ' :SwpQ %5d' \
- ' :SwpOcc %5d'
- SHAR_EOF
- fi
- if test -f 'sysinfo4.sys5'
- then
- echo shar: "will not over-write existing file 'sysinfo4.sys5'"
- else
- cat << \SHAR_EOF > 'sysinfo4.sys5'
- #! /bin/sh
-
- echo "Dumping part of the 'sysinfo' structure. Unique lines only, every 2 seconds"
-
- nlist -atu -f9d -s 2 \
- 'sysinfo+108 :Iget' \
- ' :Namei' \
- ' :Dirblks' \
- ' :Readch' \
- ' :Writech' \
- '#-2 100 * #-1 #-2 + / : "% Reads"
- SHAR_EOF
- fi
- if test -f 'sysinfo5.sys5'
- then
- echo shar: "will not over-write existing file 'sysinfo5.sys5'"
- else
- cat << \SHAR_EOF > 'sysinfo5.sys5'
- #! /bin/sh
-
- echo "Dumping part of the 'sysinfo' structure. Unique lines only, every 2 seconds"
-
- nlist -atu -f8d -s 2 \
- 'sysinfo+128 :RcvInts' \
- ' :XmtInts' \
- ' :MdmInts' \
- ' :RawCh' \
- ' :CanCh' \
- ' :OutCh' \
- ' :Msg %4d' \
- ' :Sema %4d'
- SHAR_EOF
- fi
- if test -f 'sar-s'
- then
- echo shar: "will not over-write existing file 'sar-s'"
- else
- cat << \SHAR_EOF > 'sar-s'
- #! /bin/sh
-
- LOOPS=${1:-100}
- echo "This will do what 'sar -s 1 1 ${LOOPS}' does"
-
- echo "`uname -a` `date +%D`\n"
-
- nlist -xat -f7u -s 1 -h1 -l ${LOOPS} \
- '@sysinfo' \
- '@' \
- '@' \
- '@' \
- '@#1 ^1 -' \
- '@#2 ^2 -' \
- '@#3 ^3 -' \
- '@#4 ^4 -' \
- '@#-1 #-2 #-3 #-4 +++' \
- '#6 100 * #-1 /: "%usr"' \
- '#7 100 * #-2 /: "%sys"' \
- '#8 100 * #-3 /: "%wio"' \
- '#5 100 * #-4 /: "%idle"' | \
- awk 'BEGIN {l=0; u=0; s=0; w=0; i=0} \
- {printf "%8s %7s %7s %7s %7s\n", $1, $2, $3, $4, $5} \
- $2 != "%usr" {l += 1; u += $2; s += $3; w += $4; i += $5} \
- END {printf "\nAverage %7d %7d %7d %7d\n", u/l, s/l, w/l, i/l}'
-
- SHAR_EOF
- fi
- exit 0
- # End of shell archive
- ---------------------------------- cut here -------------------------------
- --
- Chris Bertin | -- CETIA -- 150, Av Marcelin Berthelot, Z.I. Toulon-Est
- +33(94)212005 | 83088 Toulon Cedex, France
- | inria!cetia!chris
-
-
-